package framer;

import java.io.IOException;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl;
import org.eclipse.m2m.atl.core.ATLCoreException;
import org.eclipse.m2m.atl.core.emf.EMFExtractor;
import org.eclipse.m2m.atl.core.emf.EMFInjector;
import org.eclipse.m2m.atl.core.emf.EMFModelFactory;
import org.eclipse.m2m.atl.core.service.CoreService;
import org.eclipse.m2m.atl.engine.emfvm.launch.EMFVMLauncher;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.resource.UMLResource;

import framer.ui.FramerUi;

import transformations.AddChanges;
import transformations.Appl2Goals;
import transformations.Frame2Search;
import transformations.Plan2Changes;

public class Framer {
	
	public static final int BUILDING_SEARCH_SPACE = 0;
	public static final int LOADING_APPL_GOALS = 1;
	public static final int RUNNING_PLANNER = 2;
	public static final int MAKING_DIFF_MODEL = 3;
	public static final int ADD_DIFF_TO_MODEL = 4;
	public static final int DONE = 5;
	
	private String frameworkModelPath;
	private String applModelPath;
	
	private AddChanges addDiff;
	
	public static void main(String[] args) {		
		new FramerUi(new Framer());
	}
	
	public Framer(){		
		EPackage.Registry.INSTANCE.put(UMLPackage.eNS_URI, UMLPackage.eINSTANCE);
		EPackage.Registry.INSTANCE.put(EcorePackage.eNS_URI, EcorePackage.eINSTANCE);
		Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(UMLResource.FILE_EXTENSION, UMLResource.Factory.INSTANCE);
	}
	
	public void setFrameworkModelPath(String modelPath){
		frameworkModelPath = modelPath;
	}
	
	public void setApplModelPath(String modelPath){
		applModelPath = modelPath;
	}
	
	private void buildSearchSpace() throws IOException, ATLCoreException{		
		Frame2Search searchSpace = new Frame2Search();
		searchSpace.loadModels(frameworkModelPath);
		searchSpace.doFrame2Search(new NullProgressMonitor());
		searchSpace.saveModels(FramerConstants.SEARCH_SPACE_FILE);
	}
	
	private void buildApplGoals() throws IOException, ATLCoreException{		
		Appl2Goals applGoals = new Appl2Goals();
		applGoals.loadModels(applModelPath);
		applGoals.doAppl2Goals(new NullProgressMonitor());
		applGoals.saveModels(FramerConstants.APPL_GOALS_FILE);
	}
	
	private void makeModelDiff() throws IOException, ATLCoreException{
		Plan2Changes modelDiff = new Plan2Changes();
		modelDiff.loadModels(FramerConstants.PLAN_FILE, frameworkModelPath);
		modelDiff.doPlan2Changes(new NullProgressMonitor());
		modelDiff.saveModels(FramerConstants.MODEL_DIFF_FILE);
	}
	
	private void addDiffToModel() throws IOException, ATLCoreException{
		addDiff = new AddChanges();		
		addDiff.loadModels(applModelPath, FramerConstants.MODEL_DIFF_FILE);
		addDiff.doAddChanges(new NullProgressMonitor());
	}
	
	public void doTransformation(FramerUi ui){
		TransformationRunner runner = new TransformationRunner(ui);
		runner.start();
	}
	
	public void saveChangedModel(String path) throws ATLCoreException{
		addDiff.saveModels(path);
	}
	
	private class TransformationRunner extends Thread{
		private FramerUi ui;
		
		private TransformationRunner(FramerUi ui){
			this.ui = ui;
		}
		
		@Override
		public void run() {
			ui.progressUpdate(BUILDING_SEARCH_SPACE);
			try {
				buildSearchSpace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ATLCoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			ui.progressUpdate(LOADING_APPL_GOALS);
			try {
				buildApplGoals();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ATLCoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			ui.progressUpdate(RUNNING_PLANNER);
			PlannerManager p = new PlannerManager();		
			p.makePlanFile(FramerConstants.APPL_GOALS_FILE, FramerConstants.SEARCH_SPACE_FILE);
			
			ui.progressUpdate(MAKING_DIFF_MODEL);
			try {
				makeModelDiff();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ATLCoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			ui.progressUpdate(ADD_DIFF_TO_MODEL);
			try {
				addDiffToModel();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ATLCoreException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}			
			ui.progressUpdate(DONE);
		}
		
	}
}
